﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using ChampionsLeagueBets.Domain;
using ChampionsLeagueBets.Infrastructure;
using ChampionsLeagueBets.Web.Mvc.Authentication;
using ChampionsLeagueBets.Web.Mvc.Common;
using ChampionsLeagueBets.Web.Mvc.Controllers.ViewModels;
using SharpArch.NHibernate.Contracts.Repositories;
using SharpArch.NHibernate.Web.Mvc;
using MvcContrib;

namespace ChampionsLeagueBets.Web.Mvc.Controllers
{
	public class TournamentsController : Controller
	{
		private readonly IExRepository<Tournament> _tournamentRepository;
		private readonly IExRepository<TournamentUserResult> _tournamentUserResult;
		private readonly IExRepository<User> _userRepository;

		public TournamentsController(IExRepository<Tournament> tournamentRepository, IExRepository<User> userRepository, IExRepository<TournamentUserResult> tournamentUserResult)
		{
			_tournamentRepository = tournamentRepository;
			_userRepository = userRepository;
			_tournamentUserResult = tournamentUserResult;
		}

		public ActionResult Index()
        {
			if (!RightPrincipal.CurrentUser.IsAdmin) return this.RedirectToAction<HomeController>(c => c.NoRights());

			var tournaments = _tournamentRepository.GetAll();
			return View(tournaments);
        }

		public ActionResult UserTournaments()
		{
			var tournaments = _tournamentRepository.GetAll();
			return View(tournaments);
		}

		public ActionResult Create()
		{
			if (!RightPrincipal.CurrentUser.IsAdmin) return this.RedirectToAction<HomeController>(c => c.NoRights());

			return View();
		}

		[HttpPost]
		[Transaction]
		[ValidateAntiForgeryToken]
		public ActionResult Create(Tournament tournament)
		{
			if (!RightPrincipal.CurrentUser.IsAdmin) return this.RedirectToAction<HomeController>(c => c.NoRights());

			try
			{
				if(tournament.IsValid())
				{
					_tournamentRepository.SaveOrUpdate(tournament);
					
					TempData[ActionConfirmation.TempDataKey] = ActionConfirmation.CreateSuccess("Poprawnie dodano turniej.");
					return RedirectToAction("Index");
				}

				TempData[ActionConfirmation.TempDataKey] = ActionConfirmation.CreateError("Wystąpił błąd podczas dodawania turnieju.");
				return View();
			}
			catch
			{
				TempData[ActionConfirmation.TempDataKey] = ActionConfirmation.CreateError("Wystąpił błąd podczas dodawania turnieju.");
				return View();
			}
		}

		public ActionResult Edit(int id)
		{
			if (!RightPrincipal.CurrentUser.IsAdmin) return this.RedirectToAction<HomeController>(c => c.NoRights());

			var tournament = _tournamentRepository.Get(id);
			TournamentViewModel tournamentViewModel = new TournamentViewModel();
			tournamentViewModel.Tournament = tournament;
			return View(tournamentViewModel);
		}

		[HttpPost]
		[Transaction]
		public ActionResult Edit(int id, Tournament tournament)
		{
			if (!RightPrincipal.CurrentUser.IsAdmin) return this.RedirectToAction<HomeController>(c => c.NoRights());

			try
			{
				Tournament editable = _tournamentRepository.Get(id);
				if (ViewData.ModelState.IsValid)
				{
					editable.Name = tournament.Name;
					editable.StartDate = tournament.StartDate;
					editable.EndDate = tournament.EndDate;
					editable.UnitOfAccount = tournament.UnitOfAccount;
					editable.Money = tournament.Money;

					_tournamentRepository.SaveOrUpdate(editable);

					TempData[ActionConfirmation.TempDataKey] = ActionConfirmation.CreateSuccess("Poprawnie zapisano dane turnieju.");
					return RedirectToAction("Index");
				}

				TempData[ActionConfirmation.TempDataKey] = ActionConfirmation.CreateSuccess("Wystąpił błąd podczas zapisywania danych turnieju.");
				return View();
			}
			catch
			{
				TempData[ActionConfirmation.TempDataKey] = ActionConfirmation.CreateSuccess("Wystąpił błąd podczas zapisywania danych turnieju.");
				return View();
			}
		}

		[Transaction]
		public ActionResult Delete(int id)
		{
			if (!RightPrincipal.CurrentUser.IsAdmin) return this.RedirectToAction<HomeController>(c => c.NoRights());

			Tournament tournament = _tournamentRepository.Get(id);
			_tournamentRepository.Delete(tournament);
			_tournamentRepository.DbContext.CommitTransaction();

			//return this.RedirectToAction(c => c.Index());
			return PartialView("_TournamentsList", _tournamentRepository.GetAll());
		}

		public ActionResult AcceptUserGames(int id)
		{
			Tournament tournament = _tournamentRepository.Get(id);
			return View(tournament);
		}

		[Transaction]
		[HttpPost]
		public ActionResult AcceptUserGames(int id, bool accept)
		{
			Tournament tournament = _tournamentRepository.Get(id);
			User user = _userRepository.Get(RightPrincipal.CurrentUser.Id);

			TournamentUserResult tournamentUserResult = new TournamentUserResult();
			tournamentUserResult.User = RightPrincipal.CurrentUser;
			tournamentUserResult.CreateDateTime = DateTime.Now;
			tournamentUserResult.Tournament = tournament;
			tournamentUserResult.Points = 0;
			user.TournamentUserResults.Add(tournamentUserResult);


			tournamentUserResult.GameUserResults = new List<GameUserResult>();
			foreach (var game in tournament.Games)
			{
				GameUserResult gameUserResult = new GameUserResult();
				gameUserResult.CreateDate = DateTime.Now;
				gameUserResult.Game = game;
				gameUserResult.TournamentUserResult = tournamentUserResult;
				tournamentUserResult.GameUserResults.Add(gameUserResult);
			}

			_tournamentRepository.SaveOrUpdate(tournament);
			_tournamentRepository.DbContext.CommitTransaction();

			return this.RedirectToAction(c => c.UserGames(id));
		}

		public ActionResult UserGames(int id)
		{
			Tournament tournament = _tournamentRepository.Get(id);

			// Najpierw gracz musi zaakceptowac regulamin.
			if (tournament.TournamentUserResults.Where(u => u.User.Id == RightPrincipal.CurrentUser.Id).FirstOrDefault() == null)
			{
				return this.RedirectToAction(c => c.AcceptUserGames(tournament.Id));
			}

			TournamentUserResult tournamentUserResult = tournament.TournamentUserResults.Where(t => t.User.Id == RightPrincipal.CurrentUser.Id).FirstOrDefault();
			
			TournamentViewModel tournamentViewModel = new TournamentViewModel();
			tournamentViewModel.Tournament = tournament;

			foreach (var gameUserResult in tournamentUserResult.GameUserResults.Where(g => !g.IsDeleted))
			{
				if (!tournamentViewModel.GamesDictionary.ContainsKey(gameUserResult.Game.GameDate))
				{
					List<GameUserResult> gameList = new List<GameUserResult>();
					gameList.Add(gameUserResult);
					tournamentViewModel.GamesDictionary.Add(gameUserResult.Game.GameDate, gameList);
				}
				else
				{
					tournamentViewModel.GamesDictionary[gameUserResult.Game.GameDate].Add(gameUserResult);
				}
			}

			return View(tournamentViewModel);
		}

		public ActionResult UserGamesView(int id)
		{
			TournamentUserResult tournamentUserResult = _tournamentUserResult.Get(id);

			TournamentViewModel tournamentViewModel = new TournamentViewModel();
			tournamentViewModel.Tournament = tournamentUserResult.Tournament;
			tournamentViewModel.User = tournamentUserResult.User;

			foreach (var gameUserResult in tournamentUserResult.GameUserResults.Where(g => !g.IsDeleted))
			{
				if (!tournamentViewModel.GamesDictionary.ContainsKey(gameUserResult.Game.GameDate))
				{
					List<GameUserResult> gameList = new List<GameUserResult>();
					gameList.Add(gameUserResult);
					tournamentViewModel.GamesDictionary.Add(gameUserResult.Game.GameDate, gameList);
				}
				else
				{
					tournamentViewModel.GamesDictionary[gameUserResult.Game.GameDate].Add(gameUserResult);
				}
			}

			return View(tournamentViewModel);
		}

		[Transaction]
		[HttpPost]
		public ActionResult UserGames(int id, List<GameUserResult> games)
		{
			Tournament tournament = _tournamentRepository.Get(id);
			try
			{
				TournamentUserResult tournamentUserResult =
					tournament.TournamentUserResults.Where(u => u.User.Id == RightPrincipal.CurrentUser.Id).FirstOrDefault();

				// Najpierw gracz musi zaakceptowac regulamin.
				if (tournamentUserResult == null)
				{
					return this.RedirectToAction(c => c.AcceptUserGames(tournament.Id));
				}

				foreach (var gameUserResult in tournamentUserResult.GameUserResults)
				{
					foreach (var userResult in games)
					{
						if (gameUserResult.Id == userResult.Id && DateTime.Now <= gameUserResult.Game.GameDate)
						{
							gameUserResult.ResultTeamGuest = userResult.ResultTeamGuest;
							gameUserResult.ResultTeamHost = userResult.ResultTeamHost;
						}
					}
				}

				TempData[ActionConfirmation.TempDataKey] = ActionConfirmation.CreateSuccess("Poprawnie zapisano wyniki turnieju.");
				return this.RedirectToAction(c => c.UserTournaments());
			}
			catch (Exception)
			{
				TempData[ActionConfirmation.TempDataKey] = ActionConfirmation.CreateError("Wystąpił błąd podczas zapisywaniu wyników turnieju.");
				return View(tournament);
			}

		}

		public ActionResult Classification(int id)
		{
			Tournament tournament = _tournamentRepository.Get(id);
			return View(tournament);
		}
	}
}
